﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Ops.Mpc.Events;

namespace Ops.Mpc.Collections
{
    /// <summary>
    /// Specialized collection used to integrate paged data result sets with UI controls and MPC state actions.
    /// </summary>
    /// <typeparam name="T">The type of generic PagerView </typeparam>
    public class PagerView<T> : ObservableCollection<T>, ICollectionView, IPagedCollectionView, IDisposable where T : class
    {
        #region Fields
        private CultureInfo _cultureInfo = CultureInfo.InvariantCulture;
        private EventHandler _currentChanged = null;
        private CurrentChangingEventHandler _currentChanging = null;
        private EventHandler<PagerEventArgs> _getPageRequest = null;
        private EventHandler<PageChangingEventArgs> _pageChanging = null;
        private EventHandler<EventArgs> _pageChanged = null;
        private int _currentIndex = 0;
        private bool _isPageChanging = false;
        private Pager _pager;
        private SortDescriptionCollection _sortDescriptionCollection = new SortDescriptionCollection();

        #endregion

        #region Constructors
        public PagerView()
        {
            this.FiltersChanged = false;
            ((INotifyCollectionChanged)this._sortDescriptionCollection).CollectionChanged += new NotifyCollectionChangedEventHandler(OnSortDescriptionCollectionChanged);
        }

        #endregion

        #region Methods
        private void OnSortDescriptionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if(e.Action != NotifyCollectionChangedAction.Reset)
                this.Refresh();
        }

        /// <summary>
        ///  Clears the collection and fires the assoicated property changed events.
        /// </summary>
        public void Reset()
        {
            this._pager = new Pager();
            this.Clear();
            this._isPageChanging = false;
            this.OnPropertyChanged(new PropertyChangedEventArgs("TotalItemCount"));
            this.OnPropertyChanged(new PropertyChangedEventArgs("PageSize"));
            this.OnPropertyChanged(new PropertyChangedEventArgs("PageIndex"));
        }
        
        /// <summary>
        /// Fills the view with the current page of items for presentation by any bound UI components
        /// </summary>
        /// <param name="items">The items to fill the view with</param>
        public void FillCurrentPage(T[] items)
        {
            
            this.Clear();

            foreach (T item in items)
                this.Add(item);

            if (this._pageChanged != null)
                this._pageChanged(this, EventArgs.Empty);

            if (this.Count > 0)
                ((ICollectionView)this).MoveCurrentTo(this[0]);

            this._isPageChanging = false;
        }

        /// <summary>
        /// Fires a request for the current page of items.  Responding party should use the 
        /// FillCurrentPage method to respond.
        /// </summary>
        /// <param name="filterUpdate">Determines if this was called because filters have been updated and the result set needs to change</param>
        private void GetCurrentPage(bool filterUpdate)
        {
            this.OnPropertyChanged(new PropertyChangedEventArgs("PageIndex"));

            if (this.Pager != null && this._getPageRequest != null && !this._isPageChanging)
            {
                if (!filterUpdate)
                {
                    this._isPageChanging = true;

                    if (this._pageChanging != null)
                        this._pageChanging(this, new PageChangingEventArgs(this.Pager.CurrentPageIndex));
                }

                if (this._getPageRequest != null)
                {
                     this._getPageRequest(this, new PagerEventArgs() { Pager = this.Pager, FilterUpdate = filterUpdate });
                }
            }


        }

        #endregion

        #region Properties
        /// <summary>
        /// This event fires when the view is requesting a single page of result items
        /// </summary>
        public event EventHandler<PagerEventArgs> GetPageRequest
        {
            add
            {
                this._getPageRequest += value;
            }

            remove
            {
                this._getPageRequest -= value;
            }
        }

        /// <summary>
        /// The currently selected item
        /// </summary>
        public T CurrentItem
        {
            get
            {
                return ((ICollectionView)this).CurrentItem as T;
            }
        }

        /// <summary>
        /// The pager used the view to page through a result set
        /// </summary>
        public Pager Pager
        {

            get
            {
                return this._pager;
            }
            set
            {
                this._pager = value;
                this.GetCurrentPage(false);
                this.OnPropertyChanged(new PropertyChangedEventArgs("TotalItemCount"));
                this.OnPropertyChanged(new PropertyChangedEventArgs("PageSize"));
                this.OnPropertyChanged(new PropertyChangedEventArgs("PageIndex"));
            }
        }

        #endregion

        #region ICollectionView Members

        /// <summary>
        /// Determines if this view can filter
        /// </summary>
        bool ICollectionView.CanFilter
        {
            get { return false; }
        }

        /// <summary>
        /// Determines if this view can group
        /// </summary>
        bool ICollectionView.CanGroup
        {
            get { return false; }
        }

        /// <summary>
        /// Determines if this view can sort
        /// </summary>
        bool ICollectionView.CanSort
        {
            get { return true; }
        }

        bool ICollectionView.Contains(object item)
        {
            return this.Contains(item as T);
        }

        CultureInfo ICollectionView.Culture
        {
            get
            {
                return this._cultureInfo;
            }
            set
            {
                this._cultureInfo = value;
            }
        }

        event EventHandler ICollectionView.CurrentChanged
        {
            add { this._currentChanged += value; }
            remove { this._currentChanged -= value; }
        }

        event CurrentChangingEventHandler ICollectionView.CurrentChanging
        {
            add { this._currentChanging += value; }
            remove { this._currentChanging -= value; }
        }

        object ICollectionView.CurrentItem
        {
            get
            {
                if (this._currentIndex > this.Count - 1 || this._currentIndex < 0)
                    return null;
                else
                    return this[this._currentIndex];
            }
        }

        int ICollectionView.CurrentPosition
        {
            get { return this._currentIndex; }
        }

        IDisposable ICollectionView.DeferRefresh()
        {
            return new Syncronization<T>(this);
        }

        Predicate<object> ICollectionView.Filter
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        ObservableCollection<GroupDescription> ICollectionView.GroupDescriptions
        {
            get { return new ObservableCollection<GroupDescription>(); }
        }

        ReadOnlyObservableCollection<object> ICollectionView.Groups
        {
            get { return new ReadOnlyObservableCollection<object>(new ObservableCollection<object>()); }
        }

        bool ICollectionView.IsCurrentAfterLast
        {
            get { return false; }
        }

        bool ICollectionView.IsCurrentBeforeFirst
        {
            get { return false; }
        }

        bool ICollectionView.IsEmpty
        {
            get { return this.Count < 1; }
        }

        bool ICollectionView.MoveCurrentTo(object item)
        {
            int newIndex = this.IndexOf(item as T);

            if (this._currentChanging != null)
                this._currentChanging(this, new CurrentChangingEventArgs(false));
            
            this._currentIndex = newIndex;

            if (this._currentChanged != null)
                this._currentChanged(this, EventArgs.Empty);

            this.OnPropertyChanged(new PropertyChangedEventArgs("CurrentItem"));
            return true;
        }

        bool ICollectionView.MoveCurrentToFirst()
        {
            if(this.Count > 0)
                return ((ICollectionView) this).MoveCurrentTo(this[0]);

            return false;
        }

        bool ICollectionView.MoveCurrentToLast()
        {
            if(this.Count > 0)
                return ((ICollectionView)this).MoveCurrentTo(this[this.Count - 1]);

            return false;
        }

        bool ICollectionView.MoveCurrentToNext()
        {
            if (this._currentIndex + 1 < this.Count)
                return ((ICollectionView)this).MoveCurrentTo(this[this._currentIndex + 1]);

            return false;
        }

        bool ICollectionView.MoveCurrentToPosition(int position)
        {
            if (position < this.Count - 1)
                return ((ICollectionView)this).MoveCurrentTo(this[position]);
            
            return true;
        }

        bool ICollectionView.MoveCurrentToPrevious()
        {
            if( this._currentIndex - 1 > 0)
                return ((ICollectionView)this).MoveCurrentTo(this[this._currentIndex - 1]);

            return false;
        }

        public void Refresh()
        {
            this.GetCurrentPage(true);
        }

        public SortDescriptionCollection SortDescriptions
        {
            get { return this._sortDescriptionCollection; }
        }

        System.Collections.IEnumerable ICollectionView.SourceCollection
        {
            get { return this; }
        }

        #endregion

        #region IPagedCollectionView Members

        bool IPagedCollectionView.CanChangePage
        {
            get { return true;  }
        }

        bool IPagedCollectionView.IsPageChanging
        {
            get { return this._isPageChanging; }
        }

        int IPagedCollectionView.ItemCount
        {
            get 
            {
                if (this.Pager != null)
                    return this.Pager.Count;
                else
                    return this.Count;

            }
        }

        bool IPagedCollectionView.MoveToFirstPage()
        {
            if (this.Pager != null)
            {
                this.Pager.CurrentPageIndex = 0;
                this.GetCurrentPage(false);
                return true;
            }

            return false;
        }

        bool IPagedCollectionView.MoveToLastPage()
        {
            if (this.Pager != null)
            {
                this.Pager.CurrentPageIndex = this.Pager.PageCount - 1;
                this.GetCurrentPage(false);
                return true;
            }

            return false;

        }

        bool IPagedCollectionView.MoveToNextPage()
        {
            if (this.Pager != null && this.Pager.CurrentPageIndex < this.Pager.PageCount - 1)
            {
                this.Pager.CurrentPageIndex++;
                this.GetCurrentPage(false);
                return true;
            }

            return false;
        }

        bool IPagedCollectionView.MoveToPage(int pageIndex)
        {
            if (this.Pager != null && pageIndex < this.Pager.PageCount && pageIndex >= 0)
            {
                this.Pager.CurrentPageIndex = pageIndex;
                this.GetCurrentPage(false);
                return true;
            }

            return false;

        }

        bool IPagedCollectionView.MoveToPreviousPage()
        {
            if (this.Pager != null && this.Pager.CurrentPageIndex - 1 >= 0)
            {
                this.Pager.CurrentPageIndex--;
                this.GetCurrentPage(false);
                return true;
            }

            return false;

        }

        event EventHandler<EventArgs> IPagedCollectionView.PageChanged
        {
            add { this._pageChanged += value; }
            remove { this._pageChanged -= value; }
        }

        event EventHandler<PageChangingEventArgs> IPagedCollectionView.PageChanging
        {
            add { this._pageChanging += value; }
            remove { this._pageChanging -= value; }
        }

        public int PageIndex
        {
            get
            {
                if (this.Pager != null)
                    return this.Pager.CurrentPageIndex;
                else
                    return 0;
            }
        }

        public int PageSize
        {
            get
            {
                if (this.Pager != null)
                    return this.Pager.PageSize;
                else
                    return 25;
            }
            set
            {
                if (this.Pager != null)
                    this.Pager.PageSize = value;

            }
        }

        public int TotalItemCount
        {
            get
            {
                if (this.Pager != null)
                    return this.Pager.Count;
                else
                    return this.Count;

            }
        }

        private bool FiltersChanged
        {
            get;
            set;
        }
        #endregion

        public class Syncronization<T2> : IDisposable where T2 : class
        {

            public Syncronization(PagerView<T2> pagerView)
            {

            }

            #region IDisposable Members

            void IDisposable.Dispose()
            {
                
            }

            #endregion
        }








        #region IDisposable Members

        void IDisposable.Dispose()
        {
            
        }

        #endregion

 


 
    }
}
